package com.haiyou.common.system;


import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Map;

import org.springframework.util.ObjectUtils;
import org.yaml.snakeyaml.Yaml;

import com.alibaba.fastjson2.JSONObject;
import com.google.common.collect.Maps;
import com.haiyou.common.system.Properties;
import com.haiyou.common.util.yml.YmlUtils;

import lombok.Cleanup;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

/**
 * 
 * 
 * @Description: 配置中心配置基础
 * @author xingyuan
 * @date 2022年9月5日 下午12:09:34
 */
@Slf4j
public abstract class NetConfig {

	public static final String d = ".";
	
	/**
	 * properties 格式文件
	 */
	public static final String configFileType_properties = "properties";
	
	/**
	 * yml 格式文件
	 */
	public static final String configFileType_yaml = "yml";

	/**
	 * 是否加载成功
	 */
	@Getter
	@Setter
	private boolean load = false;
	
	/**
	 * 文件地址
	 */
	@Getter
	@Setter
	private String fileUrl;
	
	@Getter
	@Setter
	private String dbType;
	
	/**
	 * 缓存 key: class.simple.name  value : key:DBType ,value config
	 */
	private static Map<String, Map<String,NetConfig>> caches = Maps.newConcurrentMap();
	
	/**
	 * 配置属性缓存
	 */
	@Getter
	private Map<String, Object> propertys = Maps.newConcurrentMap();
	
	
	/**
	 * 远程文件格式
	 */
	public abstract String fileType();
	
	/**
	 * 获取 配置文件 uri 链接
	 * @return
	 */
	public abstract String getConfigFileUrl();
	
	/**
	 * 获取 class key
	 * @return
	 */
	public String getClassKey() {
		return this.getClass().getSimpleName();
	}

	public int getInt(String key,int defaultValue) {
		return (int) propertys.getOrDefault(key, defaultValue);
	}
	
	public boolean getBoolean(String key,boolean defaultValue) {
		return (boolean) propertys.getOrDefault(key, defaultValue);
	}
	
	public String getString(String key,String defaultValue) {
		return (String) propertys.getOrDefault(key, defaultValue);
	}
	
	/**
	 * 加载配置文件
	 */
	public boolean load(String dbType) {
		
		this.dbType = dbType;
		
		if(!Properties.spring_cloud_config_enabled()) {
			//本地文件模式
			String path = getLocalFileAbsolutePath();
			
			this.fileUrl = path;
			
			File[] files = new File(path).listFiles(f ->f.getName().startsWith(dbType) && f.getName().endsWith(fileType()));
			
			if(ObjectUtils.isEmpty(files)) {
				return false;
			}
			
			File file = files[0];
			
			
			try {
				@Cleanup
				FileReader fileReader = new FileReader(file);
				this.propertys = resolutionFile(fileReader);
			} catch (Exception e) {
				log.error(e.getMessage(),e);
				return false;
			}
			
			return true;
			
		}else {
			//远程文件模式
			
			String netUrl = getConfigFileUrl();
			
			
			this.fileUrl = netUrl;
			
			return loadNetFile(netUrl);
		}
		
	}	
	
	
	public static String spring_cloud_config_uri() {
		return Properties.spring_cloud_config_uri();
	}
	
	
	/**
	 * 加载数据配置
	 * @param dbType
	 */
	public boolean loadNetFile(String netUrl) {
		
		try {

			URL url = new URL(netUrl); // 创建URL
			
			URLConnection urlconn = url.openConnection(); // 试图连接并取得返回状态码
			urlconn.connect();
			HttpURLConnection httpconn = (HttpURLConnection) urlconn;
			int HttpResult = httpconn.getResponseCode();
			if (HttpResult != HttpURLConnection.HTTP_OK) {
				log.error("url:{}",url);
				log.error("访问远程配置文件失败http code:{}", HttpResult);
				return false;
			}
			
			@Cleanup
			InputStreamReader isReader = new InputStreamReader(urlconn.getInputStream(), "UTF-8");
			BufferedReader reader = new BufferedReader(isReader);
		
			this.propertys = resolutionFile(reader);
			
			return true;

		} catch (Exception e) {
			log.error(e.getMessage(), e);
			return false;
		}
	}
	
	
	private Map<String, Object> resolutionFile(Reader reader){
		Map<String, Object> maps = Maps.newHashMap();
		
		switch (fileType()) {
		case configFileType_yaml:
			Yaml yaml = new Yaml();
			Object yml = yaml.load(reader);
			YmlUtils.iterateNode(JSONObject.parseObject(JSONObject.toJSONString(yml)), "", maps);
			return maps;
		case configFileType_properties:
			try {
				java.util.Properties properties = new java.util.Properties(null);
				properties.load(reader);
				for (Object key : properties.keySet()) {
					maps.put(String.valueOf(key), properties.get(key));
				}
			} catch (Exception e) {
				log.error(e.getMessage(),e);
			}
			return maps;
		default:
			log.info("解析文件文件数据异常,未知类型:{}",fileType());
			return Maps.newHashMap();
		}
	}
	
	
	
	
	
	/**
	 * 获取本地文件地址
	 * @param dbType
	 * @return
	 */
	public abstract String getLocalFileAbsolutePath();
	
	/**
	 * 获取文件后缀
	 * @return
	 */
	public String getProfile() {
		return Properties.spring_cloud_config_profile();
	}
	
	
	/**
	 * 获取配置信息
	 * @param dbType
	 * @param classType
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T extends NetConfig> T getNetConfig(String dbType,Class<T> tClass) {
		 
		@SuppressWarnings("deprecation")
		Map<String, NetConfig> configs = caches.compute(tClass.getSimpleName(), (k,v)->{
			
			if(v == null) {
				v = Maps.newConcurrentMap();
			}
			
			v.compute(dbType, (k1,v1)->{
				
				if(v1 == null) {
					try {
						v1 = tClass.newInstance();
					} catch (Exception e) {
						log.error(e.getMessage(),e);
						return null;
					}
					v1.setLoad(v1.load(dbType));
				}
				
				return v1;
			});
			
			return v;
		});
		
		NetConfig t = configs.getOrDefault(dbType, null);
		
		if(t == null) {
			return null;
		}
		
		return (T)t;
	}
}
